home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tcl7.4 / compat / waitpid.c < prev   
Encoding:
C/C++ Source or Header  |  1994-12-18  |  4.6 KB  |  173 lines

  1. /* 
  2.  * waitpid.c --
  3.  *
  4.  *    This procedure emulates the POSIX waitpid kernel call on
  5.  *    BSD systems that don't have waitpid but do have wait3.
  6.  *    This code is based on a prototype version written by
  7.  *    Mark Diekhans and Karl Lehenbauer.
  8.  *
  9.  * Copyright (c) 1993 The Regents of the University of California.
  10.  * Copyright (c) 1994 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. #ifndef lint
  17. static char sccsid[] = "@(#) waitpid.c 1.7 94/12/17 16:26:27";
  18. #endif /* not lint */
  19.  
  20. #include "tclInt.h"
  21. #include "tclPort.h"
  22.  
  23. /*
  24.  * A linked list of the following structures is used to keep track
  25.  * of processes for which we received notification from the kernel,
  26.  * but the application hasn't waited for them yet (this can happen
  27.  * because wait may not return the process we really want).  We
  28.  * save the information here until the application finally does
  29.  * wait for the process.
  30.  */
  31.  
  32. typedef struct WaitInfo {
  33.     int pid;                /* Pid of process that exited. */
  34.     WAIT_STATUS_TYPE status;        /* Status returned when child exited
  35.                      * or suspended. */
  36.     struct WaitInfo *nextPtr;        /* Next in list of exited processes. */
  37. } WaitInfo;
  38.  
  39. static WaitInfo *deadList = NULL;    /* First in list of all dead
  40.                      * processes. */
  41.  
  42. /*
  43.  *----------------------------------------------------------------------
  44.  *
  45.  * waitpid --
  46.  *
  47.  *    This procedure emulates the functionality of the POSIX
  48.  *    waitpid kernel call, using the BSD wait3 kernel call.
  49.  *    Note:  it doesn't emulate absolutely all of the waitpid
  50.  *    functionality, in that it doesn't support pid's of 0
  51.  *    or < -1.
  52.  *
  53.  * Results:
  54.  *    -1 is returned if there is an error in the wait kernel call.
  55.  *    Otherwise the pid of an exited or suspended process is
  56.  *    returned and *statusPtr is set to the status value of the
  57.  *    process.
  58.  *
  59.  * Side effects:
  60.  *    None.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64.  
  65. #ifdef waitpid
  66. #   undef waitpid
  67. #endif
  68.  
  69. int
  70. waitpid(pid, statusPtr, options)
  71.     int pid;            /* The pid to wait on.  Must be -1 or
  72.                  * greater than zero. */
  73.     int *statusPtr;        /* Where to store wait status for the
  74.                  * process. */
  75.     int options;        /* OR'ed combination of WNOHANG and
  76.                  * WUNTRACED. */
  77. {
  78.     register WaitInfo *waitPtr, *prevPtr;
  79.     int result;
  80.     WAIT_STATUS_TYPE status;
  81.  
  82.     if ((pid < -1) || (pid == 0)) {
  83.     errno = EINVAL;
  84.     return -1;
  85.     }
  86.  
  87.     /*
  88.      * See if there's a suitable process that has already stopped or
  89.      * exited. If so, remove it from the list of exited processes and
  90.      * return its information.
  91.      */
  92.  
  93.     for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL;
  94.         prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) {
  95.     if ((pid != waitPtr->pid) && (pid != -1)) {
  96.         continue;
  97.     }
  98.     if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) {
  99.         continue;
  100.     }
  101.     result = waitPtr->pid;
  102.     *statusPtr = *((int *) &waitPtr->status);
  103.     if (prevPtr == NULL) {
  104.         deadList = waitPtr->nextPtr;
  105.     } else {
  106.         prevPtr->nextPtr = waitPtr->nextPtr;
  107.     }
  108.     ckfree((char *) waitPtr);
  109.     return result;
  110.     }
  111.  
  112.     /*
  113.      * Wait for any process to stop or exit.  If it's an acceptable one
  114.      * then return it to the caller;  otherwise store information about it
  115.      * in the list of exited processes and try again.  On systems that
  116.      * have only wait but not wait3, there are several situations we can't
  117.      * handle, but we do the best we can (e.g. can still handle some
  118.      * combinations of options by invoking wait instead of wait3).
  119.      */
  120.  
  121.     while (1) {
  122. #if NO_WAIT3
  123.     if (options & WNOHANG) {
  124.         return 0;
  125.     }
  126.     if (options != 0) {
  127.         errno = EINVAL;
  128.         return -1;
  129.     }
  130.     result = wait(&status);
  131. #else
  132.     result = wait3(&status, options, 0);
  133. #endif
  134.     if ((result == -1) && (errno == EINTR)) {
  135.         continue;
  136.     }
  137.     if (result <= 0) {
  138.         return result;
  139.     }
  140.  
  141.     if ((pid != result) && (pid != -1)) {
  142.         goto saveInfo;
  143.     }
  144.     if (!(options & WUNTRACED) && (WIFSTOPPED(status))) {
  145.         goto saveInfo;
  146.     }
  147.     *statusPtr = *((int *) &status);
  148.     return result;
  149.  
  150.     /*
  151.      * Can't return this info to caller.  Save it in the list of
  152.      * stopped or exited processes.  Tricky point: first check for
  153.      * an existing entry for the process and overwrite it if it
  154.      * exists (e.g. a previously stopped process might now be dead).
  155.      */
  156.  
  157.     saveInfo:
  158.     for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) {
  159.         if (waitPtr->pid == result) {
  160.         waitPtr->status = status;
  161.         goto waitAgain;
  162.         }
  163.     }
  164.     waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo));
  165.     waitPtr->pid = result;
  166.     waitPtr->status = status;
  167.     waitPtr->nextPtr = deadList;
  168.     deadList = waitPtr;
  169.  
  170.     waitAgain: continue;
  171.     }
  172. }
  173.